home *** CD-ROM | disk | FTP | other *** search
- /* #Specification: mailconf / complex user routing / strategy
- The /etc/aliases mecanims allows one to redirect email to another user
- once it is knows that the email is for this user on this system.
-
- The /var/lib/mailertable mecanism allows one to redirect email for
- a complete domain to another email server.
-
- The complex user routing is a special case allowing you to redirect
- email based on user name and domain name. This was created for
- ISP hosting virtual domain both for WWW and email. This mecanism can
- differentiate between info@virtual1.com and info@virtual2.com.
-
- This capability is achieved by generating sendmail.cf rules directly.
- */
- #include <stdio.h>
- #include <string.h>
- #include "mailconf.h"
- #include "internal.h"
- #include "mailconf.m"
-
- static MAILCONF_HELP_FILE help_cplx ("complex");
-
- PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE(
- const char *buf)
- {
- SSTRING act;
- buf = str_extract (buf,act);
- active = act.getval();
- buf = str_extract (buf,from);
- buf = str_extract (buf,to);
- buf = str_extract (buf,new_from);
- buf = str_extract (buf,new_to);
- buf = str_extract (buf,router);
- buf = str_extract (buf,mailer);
- buf = str_extract (buf,comment);
- }
-
- PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE()
- {
- active = 1;
- mailer.setfrom ("esmtp");
- }
-
- /*
- Edit one rule, return 0 if the edit was successful
- return 1 if this record should be deleted.
- */
- PUBLIC int COMPLEX_ROUTE::edit()
- {
- int ret = -1;
- DIALOG dia;
- dia.newf_chk ("",active,MSG_U(F_CPLXACTIVE,"This rule is active"));
- //dia.newf_str (MSG_U(F_FROM,"from (opt)"),from);
- dia.newf_str (MSG_U(F_TO,"to"),to);
- //dia.newf_str (MSG_U(F_NEWFROM,"new from (opt)"),new_from);
- dia.newf_str (MSG_U(F_NEWTO,"rewriten to"),new_to);
- dia.newf_str (MSG_U(F_ROUTER,"Forward to server(opt)"),router);
- FIELD_COMBO *comb = dia.newf_combo (MSG_R(F_MAILER),mailer);
- dia.newf_str (MSG_U(F_COMMENT,"Comment"),comment);
-
- dia.delwhat (MSG_U(F_DELCPLX,"delete the record"));
- basic_setmailer (comb);
- int nof = 0;
- while (1){
- char buf[100];
- if (to.is_empty()){
- strcpy (buf,MSG_U(T_NEWCOMPLEXROUTE,"New complex route"));
- }else{
- sprintf (buf,MSG_U(T_COMPLEXROUTE,"complex routing for %s")
- ,to.get());
- }
- MENU_STATUS code = dia.edit (buf
- ,MSG_U(I_COMPLEXROUTE
- ,"You are allowed to intercept email going to a user\n"
- "and redirect this to a new mail server,\n"
- "using a different protocol.\n"
- "In the process, you can rewrite the TO field\n"
- "and even the from field\n")
- ,help_cplx
- ,nof
- ,MENUBUT_DEL|MENUBUT_ACCEPT|MENUBUT_CANCEL);
- if (code == MENU_CANCEL || code == MENU_ESCAPE){
- dia.restore();
- break;
- }else if (code == MENU_DEL){
- ret = 1;
- break;
- }else{
- char status[2000];
- if (rule0(NULL,status)==-1){
- xconf_error ("%s",status);
- }else{
- ret = 0;
- break;
- }
- }
- }
- return ret;
- }
-
-
- static const char CPLXMAIL[]="cplxmail";
- static const char CASES[]="cases";
-
-
-
- PUBLIC COMPLEX_ROUTES::COMPLEX_ROUTES()
- {
- SSTRINGS strs;
- int nb = linuxconf_getall (CPLXMAIL,CASES,strs,0);
- for (int i=0; i<nb; i++){
- add (new COMPLEX_ROUTE(strs.getitem(i)->get()));
- }
- rstmodified();
- }
-
- PUBLIC COMPLEX_ROUTE *COMPLEX_ROUTES::getitem(int no)
- {
- return (COMPLEX_ROUTE*)ARRAY::getitem(no);
- }
-
- PUBLIC void COMPLEX_ROUTES::save()
- {
- linuxconf_removeall (CPLXMAIL,CASES);
- int n = getnb();
- for (int i=0; i<n; i++){
- COMPLEX_ROUTE *c = getitem(i);
- char buf[1000];
- sprintf (buf,"%d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\""
- ,c->active
- ,c->from.get(),c->to.get()
- ,c->new_from.get(),c->new_to.get()
- ,c->router.get(),c->mailer.get()
- ,c->comment.get());
- linuxconf_add (CPLXMAIL,CASES,buf);
- }
- if (linuxconf_save()!=-1){
- rstmodified();
- }
- }
-
- static int cmp_by_to (const ARRAY_OBJ *p1, const ARRAY_OBJ *p2)
- {
- COMPLEX_ROUTE *r1 = (COMPLEX_ROUTE*)p1;
- COMPLEX_ROUTE *r2 = (COMPLEX_ROUTE*)p2;
- int ret = r1->to.cmp(r2->to);
- if (ret == 0) ret = r1->from.cmp(r2->from);
- return ret;
- }
-
- PUBLIC int COMPLEX_ROUTES::edit()
- {
- int ret = 0;
- int nof = 0;
- while (1){
- sort(cmp_by_to);
- DIALOG dia;
- int n = getnb();
- for (int i=0; i<n; i++){
- COMPLEX_ROUTE *cp = getitem(i);
- dia.new_menuitem (cp->to,cp->new_to);
- }
- dia.addwhat (MSG_U(T_ADDCPLX,"A complex routing rule"));
- MENU_STATUS code = dia.editmenu (MSG_U(T_COMPLEXROUTES,"Complex routings")
- ,MSG_U(I_COMPLEXROUTES
- ,"You can setup multiple complex routing for email\n"
- "The key is the destination, including the user name\n")
- ,help_cplx
- ,nof
- ,MENUBUT_ADD);
- if (code == MENU_QUIT || code == MENU_ESCAPE){
- break;
- }else if (code == MENU_OK){
- if (nof >=0 && nof < n){
- COMPLEX_ROUTE *cp = getitem(nof);
- int status = cp->edit();
- if (status==1){
- remove_del(cp);
- }else if (status == 0){
- save();
- ret = 1;
- }
- }
- }else if (code == MENU_ADD){
- COMPLEX_ROUTE *cp = new COMPLEX_ROUTE;
- if (cp->edit()==0){
- add (cp);
- save();
- ret = 1;
- }else{
- delete cp;
- }
- }
- }
- return ret;
- }
-
- /*
- Return != 0 if some entry were modified
- */
- int complex_edit ()
- {
- COMPLEX_ROUTES cpl;
- return cpl.edit();
- }
-
- /*
- Split and validate an addres of the form user@domain
- */
- static int complex_parse (
- const SSTRING &adr,
- char *user,
- char *site)
- {
- int ret = -1;
- char buf[200];
- adr.copy (buf);
- user[0] = site[0] = '\0';
- char *pt = strchr (buf,'@');
- if (pt != NULL){
- *pt++ = '\0';
- strcpy (user,buf);
- strcpy (site,pt);
- ret = 0;
- }
- return ret;
- }
-
- /*
- Generate the rules to be insert in the ruleset 0 of sendmail.cf.
- if fout == NULL, this function is simply called to validate the
- rule.
- */
- PUBLIC int COMPLEX_ROUTE::rule0(FILE *fout, char *status)
- {
- /* #Specification: mailconf / complex user routing / inactive
- An inactive rule is not validated. This means the user may
- left a rules half finished.
- */
- int ret = 0;
- status[0] = '\0';
- if (active){
- ret = 0;
- char userto[200],siteto[200];
- userto[0] = siteto[0] = '\0';
- if (to.is_empty()){
- status += sprintf (status
- ,MSG_U(F_NOEMPTY,"Field \"%s\" can't be empty\n")
- ,MSG_R(F_TO));
- ret = -1;
- }else if (complex_parse (to,userto,siteto) == -1){
- ret = -1;
- status += sprintf (status
- ,MSG_U(F_IVLDTO,"Field \"%s\" is invalid or incomplete\n"
- " Was expecting user@domain format\n")
- ,MSG_R(F_TO));
- }
- char new_userto[200],new_siteto[200];
- new_userto[0] = new_siteto[0] = '\0';
- int localhost = 0;
- if (new_to.is_empty()){
- status += sprintf (status
- ,MSG_R(F_NOEMPTY)
- ,MSG_R(F_NEWTO));
- ret = -1;
- }else if (new_to.strchr('@')==NULL){
- /* #Specification: mailconf / complex routing / new to no site
- If the "rewritten to" field only contain a name (without @)
- it is taken as a local user name. This is especially useful
- when hosting virtual domain and you have the setup
-
- #
- info@virtual1.com -> info1
- info@virtual2.com -> joewho
- #
- */
- localhost = 1;
- new_to.copy (new_userto);
- }else if (complex_parse (new_to,new_userto,new_siteto)==-1){
- ret = -1;
- status += sprintf (status,MSG_R(F_IVLDTO),MSG_R(F_NEWTO));
- }
- char str_router[200];
- if (router.is_empty()){
- strcpy (str_router,new_siteto);
- }else{
- router.copy(str_router);
- }
- if (!localhost && mailer.is_empty()){
- status += sprintf (status
- ,MSG_R(F_NOEMPTY)
- ,MSG_R(F_MAILER));
- ret = -1;
- }
- if (fout != NULL && ret == 0){
- char *pt = "";
- // Another rule in case the domain is qualified by the dns
- // and a . has been added.
- for (int i=0; i<2; i++, pt = "."){
- if (localhost){
- fprintf (fout,"R%s<@%s%s>\t$#local $: @ %s\n"
- ,userto,siteto,pt
- ,new_userto);
-
- }else{
- fprintf (fout,"R%s<@%s%s>\t$#%s $@%s $: %s < @ %s>\n"
- ,userto,siteto,pt
- ,mailer.get(),str_router
- ,new_userto,new_siteto);
- }
- }
- }
- }
- return ret;
- }
-
- /*
- Generate the require parts of ruleset 0.
- Return -1 if any errors.
- */
- PUBLIC int COMPLEX_ROUTES::rule0(FILE *fout)
- {
- int ret = 0;
- int n = getnb();
- for (int i=0; i<n; i++){
- COMPLEX_ROUTE *c = getitem(i);
- char status[10000];
- ret |= c->rule0(fout,status);
- }
- return ret;
- }
-
-